#include "serialportconnection.h"
#include "ui_serialportconnection.h"

#include<qDebug>
Q_GLOBAL_STATIC(SerialPortConnection,theInstance)
SerialPortConnection::SerialPortConnection(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::SerialPortConnection)
{
    ui->setupUi(this);

    initSerialport();
    openSerialPort();


    connect(m_serialPort,&QSerialPort::readyRead,this,&SerialPortConnection::receiveModsimData);

   // connect(SerialPortConnection::m_serialPort,&QSerialPort::readyRead,this,&SerialPortConnection::receiveModsimData);
    qDebug()<<"initSerialport";
    // connect(m_serialPort, &QSerialPort::readyRead, this, &SerialPortConnection::handleReadyRead);
    // connect(m_serialPort, &QSerialPort::errorOccurred, this, &SerialPortConnection::handleError);




}

SerialPortConnection::~SerialPortConnection()
{
    delete ui;
}

SerialPortConnection *SerialPortConnection::instance()
{
    return theInstance;
}

void SerialPortConnection::handleReadyRead()
{
    const QByteArray data = m_serialPort->readAll();
    if (!data.isEmpty()) {
        emit dataReceived(data);
    }




}

void SerialPortConnection::handleError(QSerialPort::SerialPortError error)//串口处理错误函数
{

    if (error == QSerialPort::NoError) return;
    const QString errorString = m_serialPort->errorString();
    emit errorOccurred(errorString);
    closeSerialPort();




}

bool SerialPortConnection::openSerialPort()
{
    if(m_portName.isEmpty())
    {
        emit errorOccurred("port name is empty!");
        return false;
    }

    m_serialPort->setPortName(m_portName);//设置串口名
    m_serialPort->setBaudRate(m_baudRate);//设置串口波特率
    m_serialPort->setDataBits(m_dataBits);//设置数据位
    m_serialPort->setStopBits(m_stopBits);//设置停止位
    m_serialPort->setParity(m_parity);//设置校验位
    m_serialPort->setFlowControl(m_flowControl);//设置串口的流控制
    // 尝试以读写模式打开串口
    if (m_serialPort->open(QIODevice::ReadWrite))
    {
        qDebug() << "串口打开成功！";

      return true;
        // 串口操作...
    }
    else
    {
        qDebug() << "打开失败，错误：" << m_serialPort->errorString();

        // 根据错误类型细化处理
        switch (m_serialPort->error())
        {
        case QSerialPort::DeviceNotFoundError:
            qDebug() << "错误原因：设备不存在。";
            break;
        case QSerialPort::PermissionError:
            qDebug() << "错误原因：权限不足。";
            break;
        case QSerialPort::OpenError:
            qDebug() << "错误原因：串口已被打开。";
            break;
        default:
            qDebug() << "未知错误。";
            break;
        }

    }


return false;










}

void SerialPortConnection::closeSerialPort()//关闭串口
{

    if (m_serialPort->isOpen())
    {
        m_serialPort->close();
        emit portOpened(false);
    }
}

void SerialPortConnection::setPortName(const QString &portName)
{
    m_portName=portName;//设置串口名;
}

void SerialPortConnection::setBaudRate(QSerialPort::BaudRate baudRate)
{

    m_baudRate=baudRate;//设置串口波特率


}

void SerialPortConnection::setDataBits(QSerialPort::DataBits dataBits)
{
    m_dataBits=dataBits;//设置串口数据位
}

void SerialPortConnection::setStopBits(QSerialPort::StopBits stopBits)
{
    m_stopBits=stopBits;//设置串口停止位
}

void SerialPortConnection::setParity(QSerialPort::Parity parity)
{
    m_parity=parity;//设置串口奇偶校验位
}

void SerialPortConnection::setFlowControl(QSerialPort::FlowControl flowControl)
{
    m_flowControl=flowControl;//设置串口流控制
}

qint64 SerialPortConnection::writeData(const QByteArray &data)
{

    if (!m_serialPort->isOpen()) {
        emit errorOccurred(tr("Port is not open!"));
        return -1;
    }
    return m_serialPort->write(data);



}

QStringList SerialPortConnection::availablePorts()
{

    QStringList ports;
    const auto infos = QSerialPortInfo::availablePorts();
    for (const QSerialPortInfo &info : infos) {
        ports << info.portName();

    }
    return ports;




}

void SerialPortConnection::initSerialport()
{

    m_serialPort=new QSerialPort(this);
    setPortName("COM2");
    setBaudRate(QSerialPort::Baud9600);
    setDataBits(QSerialPort::Data8);
    setStopBits(QSerialPort::OneStop);
    setParity(QSerialPort::NoParity);
    setFlowControl(QSerialPort::NoFlowControl);



}

void SerialPortConnection::readModsimData()
{
    initSendMessageO(slaveAddress,functionCode,startAddress,numRegisters);
    QByteArray request;
    initQByteArrayData(request);
    quint16 _CRC16=caculateCRC16(request);
    request.append(_CRC16&0xFF);
    request.append(_CRC16>>8&0xff);
    m_serialPort->write(request);//串口发送请求帧
    qDebug()<<request;
}

void SerialPortConnection::initQByteArrayData(QByteArray &Data)
{


    Data.append(slaveAddress);
    Data.append(functionCode);
    Data.append((startAddress >> 8) & 0xFF);  // 高字节在前（大端序）
    Data.append(startAddress & 0xFF);
    Data.append((numRegisters >> 8) & 0xFF);
    Data.append(numRegisters & 0xFF);




}




quint16 SerialPortConnection::caculateCRC16(QByteArray &Data)
{


    quint16 CRC16=0xffff;//crc初始值
    for(int i=0;i<Data.size();i++)
    {
        CRC16^=(quint8)Data[i];//按字节异或
        for(int j=0;j<8;++j)
        {

            if(CRC16&0x0001)//检查最低位是否为1
            {
                CRC16>>=1;
                CRC16^=0xA001;
            }
            else{
                CRC16>>1;
            }
        }



    }
    return CRC16;
}

void SerialPortConnection::initSendMessageO(quint8 &slaveAddress, quint8 &functionCode, quint16 &startAddress, quint16 &numRegisters)
{
     slaveAddress = 0x01;
     functionCode = 0x03;
     startAddress = 0;     // 起始地址 0
     numRegisters = 2;      // 读取 2 个寄存器
}

void SerialPortConnection::receiveModsimData()
{
   qDebug()<<"receiveModsimData";
    static QByteArray responseData;
    responseData+=m_serialPort->readAll();
    //检查数据长度是否足够
    if(responseData.size()<5)//最小响应长度；5字节
        return ;
    //解析响应头
    quint8 receiveslaveId=(quint8)responseData[0];
    quint8  receiveCodeID=(quint8)responseData[1];
    quint8  byteCount=(quint8)responseData[2];
    //  计算完整响应帧长度（字节数 + 头3字节 + CRC2字节）
    int expectedLength =3+byteCount+2;
    if(responseData.size()<expectedLength)
        return;
    //提取CRC校验
    quint8  receivedCRC=(quint8)responseData[expectedLength-2]|((quint8)responseData[expectedLength-1<<8]);
    //校验CRC16
    QByteArray dataForCRC=responseData.left(expectedLength-2);
    quint16 calculatedCRC=caculateCRC16(dataForCRC);

    if(receivedCRC!=calculatedCRC)
    {
        qDebug()<<"CRC 校验失败";
        responseData.clear();
        return;

    }
    // 解析数据（每个寄存器2字节，大端序）
    QVector<quint16> registers;
    for(int i=0;i<byteCount;i+=2)
    {
        quint16 value=((quint8)responseData[3+i]<<8)|(quint8)responseData[4+i];

        registers.append(value);
    }
    qDebug() << "读取到的 Holding Registers：" << registers;

    responseData.clear(); // 清空缓存

}
